// Transaction: 用于管理 Promise 链的一个类
// new Transaction([
//   [name,function],
//   [name,function],
//   [name,function],
// ])
// 在 function 中接收的参数为整个 _PromiseMap, 通过对应的 name 来调用那个 function 的返回结果
import compose from 'koa-compose';

export default class Transaction {
    _functionMap = new Map(); // 储存所有存入的函数

    constructor(initMapArray = new Map()) {
        this._functionMap = initMapArray instanceof Map ? initMapArray : new Map(initMapArray);
    }
    async run(...args) {
        const _PromiseMap = new Map(); // 存储所有的结果
        let LastResult; //存储上一个结果
        return [...this._functionMap.entries()].reduce((promise, [name, cur]) => {
            return promise.then(async (_PromiseMap) => {
                let result = await this._compose(cur, name).apply(this, [_PromiseMap, LastResult, ...args]);
                _PromiseMap.set(name, result);
                LastResult = result;
                return _PromiseMap;
            });
        }, Promise.resolve(_PromiseMap));
    } // 开始执行 Promise 链的启动函数

    // 注意，array => promise line , 设置的 func 都应该是纯函数
    set(name, func) {
        this._functionMap.set(name, func);
    }
    _plugins = [];
    _compose(func, name) {
        return (...args) =>
            new Promise((resolve, reject) => {
                try {
                    compose([
                        ...this._plugins,
                        async ([_, ...data], next) => {
                            try {
                                const result = await func.apply(null, data);
                                resolve(result);
                                await next();
                            } catch (err) {
                                reject(err);
                            }
                        },
                    ])([name, ...args]);
                } catch (err) {
                    reject(err);
                }
            });
    }
    use(plugin) {
        this._plugins.push(plugin);
        return this;
    }
}
